<!DOCTYPE html>
<html lang="zh-Hans">
  <head>
    <meta charset="UTF-8" />
    <!-- 强制让文档的宽度与设备的宽度保持1:1，并且文档最大的宽度比例是1.0，且不允许用户点击屏幕放大浏览；user-scalable: 用户是否可以手动缩放 -->
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
    />
    <!-- iphone设备中的safari私有meta标签，它表示：允许全屏模式浏览 -->
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <!-- iphone的私有标签，它指定的iphone中safari顶端的状态条的样式 -->
    <meta content="black" name="apple-mobile-web-app-status-bar-style" />
    <!-- 忽略数字自动识别为电话号码 -->
    <meta content="telephone=no" name="format-detection" />
    <!-- 忽略识别邮箱 -->
    <meta content="email=no" name="format-detection" />
    <!-- 添加智能 App 广告条 Smart App Banner：告诉浏览器这个网站对应的app，并在页面上显示下载banner -->
    <meta
      name="apple-itunes-app"
      content="app-id=myAppStoreID, affiliate-data=myAffiliateData, app-argument=myURL"
    />
    <!--- 让360浏览器使用Google Chrome Frame  content="ie-comp"ie兼容内核,ie6/7旧版本 content="ie-stand"ie标准内核,ie新版本 -->
    <meta name="renderer" content="webkit" />
    <!-- 优先使用 IE 最新版本和 Chrome -->
    <meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1" />
    <!-- 禁止百度转码 -->
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <!-- UC浏览器强制竖屏 portrait 为横屏,landscape 为竖屏 -->
    <meta name="screen-orientation" content="landscape" />
    <!-- QQ浏览器设置横屏、竖屏显示，portrait 横屏，landscape 竖屏-->
    <meta name="x5-orientation" content="landscape" />
    <title>01.树结构搜索</title>
    <!-- 指定文档生成的工具名称 -->
    <meta name="Generator" content="Visual Studio Code" />
    <meta name="Author" content="zhaoshouxin" />
    <meta
      name="website"
      content="https://developer.mozilla.org/zh-CN/docs/Web/API"
    />
    <meta name="Description" content="搜索引擎用" />
    <link
      href="https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css"
      rel="stylesheet"
    />
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
  </head>
  <style>
    [v-cloak] {
      display: none;
    }
  </style>
  <body>
    <h1>01.树结构搜索</h1>
  </body>
  <!-- <script src="https://unpkg.com/vue@next"></script> -->
  <!-- <script>
    //创建Vue实例,得到 ViewModel
    const app = Vue.createApp({
      data() {
        return {
          msg: "赵守鑫",
        };
      },
    }).mount("#app");
  </script> -->
</html>
<script>
  /**
   * docs   ----
   * 根据关键字搜索name匹配的数据，用与树结构
   * 如果某个对象的name满足匹配结果，则保留他的父元素，并保留他所有的子元素
   * 该方法一般用于自己写前端树搜索或类似elementui 中的级联选择器搜索，得到的结果可保留上下级对象
   * ----
   * params  ---
   * data结构 [{
   * id : '1',//当前对象id
   * pid : '0',// 当前对象父节点id
   * name : '测试',// 当前节点对象名称，搜索也搜索该名称
   * children : [...]
   * }]
   * 根接的点pid为0，data中可以不出现根节点对象
   * 无限层级
   * ----
   */
  const filter_tree_by_name = (data, searchTerm) => {
    const deepClone = (obj) => JSON.parse(JSON.stringify(obj));
    // 查找节点的辅助函数
    const findById = (list, id) => list.find((node) => node.id === id);
    // 递归过滤树
    const filterNodes = (nodes, parentId = "0") => {
      let result = [];
      nodes.forEach((node) => {
        if (node.name.includes(searchTerm)) {
          // 如果节点名称包含搜索词，则深克隆该节点
          const newNode = deepClone(node);
          if (newNode.children) {
            // 递归处理子节点
            newNode.children = filterNodes(newNode.children, newNode.id);
          }
          result.push(newNode);
        } else if (node.children) {
          // 如果当前节点不匹配但有子节点，递归搜索子节点
          const filteredChildren = filterNodes(node.children, node.id);
          if (filteredChildren.length > 0) {
            // 如果子节点中有匹配的，保留当前节点并更新其子节点为过滤后的子节点
            const newNode = deepClone(node);
            newNode.children = filteredChildren;
            result.push(newNode);
          }
        }
      });
      // 合并重复的节点
      let uniqueMatches = [];
      result.forEach((node) => {
        if (!findById(uniqueMatches, node.id)) {
          uniqueMatches.push(node);
        } else {
          const existingNode = findById(uniqueMatches, node.id);
          node.children.forEach((child) => {
            if (!findById(existingNode.children, child.id)) {
              existingNode.children.push(child);
            }
          });
        }
      });
      return uniqueMatches.filter((node) => {
        // 仅返回顶级节点或其父节点不在列表中的节点
        return parentId === "0" || !findById(uniqueMatches, parentId);
      });
    };
    return filterNodes(data);
  };

  // 调用
  let data = [
    {
      id: "1", //当前对象id
      pid: "0", // 当前对象父节点id
      name: "测试", // 当前节点对象名称，搜索也搜索该名称
      children: [
        {
          id: "1-1",
          pid: "1",
          name: "0-1",
          children: [
            {
              id: "1-1-1",
              pid: "1-1",
              name: "0-1-1",
            },
          ],
        },
      ],
    },
    {
      id: "2",
      pid: "0",
      name: "测试-2",
      children: [
        {
          id: "2-1",
          pid: "2",
          name: "测试-2-1",
        },
      ],
    },
  ];
  //   data.value = filter_tree_by_name(data.value, "测试");
  let res = filter_tree_by_name(data, "测试");
  console.log("树形结构搜索", res);
</script>
